﻿using System;
using System.Text;
using System.Runtime.InteropServices;
using System.Reflection;
 
using System.Diagnostics;
using System.Windows.Forms;
using System.Drawing;
namespace Scada.MouseKeyboardLibrary
{
    namespace MouseKeyboardLibrary
    {
        /// <summary>  
        /// Abstract base class for Mouse and Keyboard hooks  
        /// </summary>  
        public abstract class GlobalHook
        {
            #region Windows API Code  
            [StructLayout(LayoutKind.Sequential)]
            protected class POINT
            {
                public int x;
                public int y;
            }
            [StructLayout(LayoutKind.Sequential)]
            protected class MouseHookStruct
            {
                public POINT pt;
                public int hwnd;
                public int wHitTestCode;
                public int dwExtraInfo;
            }
            [StructLayout(LayoutKind.Sequential)]
            protected class MouseLLHookStruct
            {
                public POINT pt;
                public int mouseData;
                public int flags;
                public int time;
                public int dwExtraInfo;
            }
            [StructLayout(LayoutKind.Sequential)]
            protected class KeyboardHookStruct
            {
                public int vkCode;
                public int scanCode;
                public int flags;
                public int time;
                public int dwExtraInfo;
            }
            [DllImport("user32.dll", CharSet = CharSet.Auto,
               CallingConvention = CallingConvention.StdCall, SetLastError = true)]
            protected static extern int SetWindowsHookEx(
                int idHook,
                HookProc lpfn,
                IntPtr hMod,
                int dwThreadId);
            [DllImport("user32.dll", CharSet = CharSet.Auto,
                CallingConvention = CallingConvention.StdCall, SetLastError = true)]
            protected static extern int UnhookWindowsHookEx(int idHook);
            [DllImport("user32.dll", CharSet = CharSet.Auto,
                 CallingConvention = CallingConvention.StdCall)]
            protected static extern int CallNextHookEx(
                int idHook,
                int nCode,
                int wParam,
                IntPtr lParam);
            [DllImport("user32")]
            protected static extern int ToAscii(
                int uVirtKey,
                int uScanCode,
                byte[] lpbKeyState,
                byte[] lpwTransKey,
                int fuState);
            /// <summary>
            /// 取得当前线程编号
            /// </summary>
            /// <returns></returns>
            [DllImport("kernel32.dll")]
            private static extern int GetCurrentThreadId();
            /// <summary>
            /// 获取扩展模块
            /// </summary>
            /// <param name="module"></param>
            /// <returns></returns>
            [DllImport("kernel32.dll", CharSet = CharSet.Auto)]
            public static extern IntPtr GetModuleHandle(string lpModuleName);

 
            [DllImport("user32")]
            protected static extern int GetKeyboardState(byte[] pbKeyState);
            [DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
            protected static extern short GetKeyState(int vKey);
            protected delegate int HookProc(int nCode, int wParam, IntPtr lParam);
            protected const int WH_MOUSE_LL = 14;
            protected const int WH_KEYBOARD_LL = 13;
            protected const int WH_MOUSE = 7;
            protected const int WH_KEYBOARD = 2;
            protected const int WM_MOUSEMOVE = 0x200;
            protected const int WM_LBUTTONDOWN = 0x201;
            protected const int WM_RBUTTONDOWN = 0x204;
            protected const int WM_MBUTTONDOWN = 0x207;
            protected const int WM_LBUTTONUP = 0x202;
            protected const int WM_RBUTTONUP = 0x205;
            protected const int WM_MBUTTONUP = 0x208;
            protected const int WM_LBUTTONDBLCLK = 0x203;
            protected const int WM_RBUTTONDBLCLK = 0x206;
            protected const int WM_MBUTTONDBLCLK = 0x209;
            protected const int WM_MOUSEWHEEL = 0x020A;
            protected const int WM_KEYDOWN = 0x100;
            protected const int WM_KEYUP = 0x101;
            protected const int WM_SYSKEYDOWN = 0x104;
            protected const int WM_SYSKEYUP = 0x105;
            protected const byte VK_SHIFT = 0x10;
            protected const byte VK_CAPITAL = 0x14;
            protected const byte VK_NUMLOCK = 0x90;
            protected const byte VK_LSHIFT = 0xA0;
            protected const byte VK_RSHIFT = 0xA1;
            protected const byte VK_LCONTROL = 0xA2;
            protected const byte VK_RCONTROL = 0x3;
            protected const byte VK_LALT = 0xA4;
            protected const byte VK_RALT = 0xA5;
            protected const byte LLKHF_ALTDOWN = 0x20;
            #endregion
            #region Private Variables  
            protected int _hookType;
            protected int _handleToHook;
            protected bool _isStarted;
            protected HookProc _hookCallback;
            #endregion
            #region Properties  
            public bool IsStarted
            {
                get
                {
                    return _isStarted;
                }
            }
            #endregion
            #region Constructor  
            public GlobalHook()
            {
                
            }
            #endregion
            #region Methods  
            public void Start(Form main)
            {
                if (!_isStarted &&
                    _hookType != 0)
                {
                    // Make sure we keep a reference to this delegate!  
                    // If not, GC randomly collects it, and a NullReference exception is thrown  
                    _hookCallback = new HookProc(HookCallbackProcedure);
                    _handleToHook = SetWindowsHookEx(
                        _hookType,
                        _hookCallback,
                       GetModuleHandle(Process.GetCurrentProcess().MainModule.ModuleName),
                        0);
                    // Were we able to sucessfully start hook?  
                    if(_handleToHook!=0)
                    {
                        _isStarted = true;
                    
                        if (main.ParentForm != null)
                        {
                            main.ParentForm.Opacity = 0;
                        }
                        else
                        {
                            main.Opacity = 0;
                        }
                    }
                    else
                    {
                        MessageBox.Show("注册钩子函数失败");
                    }
                    
                  
                }
            }
            public void Stop()
            {
                if (_isStarted)
                {
                    UnhookWindowsHookEx(_handleToHook);
                    _isStarted = false;
                }
            }
            protected virtual int HookCallbackProcedure(int nCode, Int32 wParam, IntPtr lParam)
            {
                // This method must be overriden by each extending hook  
                return 0;
            }
           
            #endregion
        }
        public class KeyboardHook : GlobalHook
        {
            #region Events  
            public event KeyEventHandler KeyDown;
            public event KeyEventHandler KeyUp;
            public event KeyPressEventHandler KeyPress;
            #endregion
            #region Constructor  
            public KeyboardHook()
            {
                _hookType = WH_KEYBOARD_LL;
            }
            #endregion
            #region Methods  
            protected override int HookCallbackProcedure(int nCode, int wParam, IntPtr lParam)
            {
                bool handled = false;
                if (nCode > -1 && (KeyDown != null || KeyUp != null || KeyPress != null))
                {
                    KeyboardHookStruct keyboardHookStruct =
                        (KeyboardHookStruct)Marshal.PtrToStructure(lParam, typeof(KeyboardHookStruct));
                    // Is Control being held down?  
                    bool control = ((GetKeyState(VK_LCONTROL) & 0x80) != 0) ||
                                   ((GetKeyState(VK_RCONTROL) & 0x80) != 0);
                    // Is Shift being held down?  
                    bool shift = ((GetKeyState(VK_LSHIFT) & 0x80) != 0) ||
                                 ((GetKeyState(VK_RSHIFT) & 0x80) != 0);
                    // Is Alt being held down?  
                    bool alt = ((GetKeyState(VK_LALT) & 0x80) != 0) ||
                               ((GetKeyState(VK_RALT) & 0x80) != 0);
                    // Is CapsLock on?  
                    bool capslock = (GetKeyState(VK_CAPITAL) != 0);
                    // Create event using keycode and control/shift/alt values found above  
                    KeyEventArgs e = new KeyEventArgs(
                        (Keys)(
                            keyboardHookStruct.vkCode |
                            (control ? (int)Keys.Control : 0) |
                            (shift ? (int)Keys.Shift : 0) |
                            (alt ? (int)Keys.Alt : 0)
                            ));
                    // Handle KeyDown and KeyUp events  
                    switch (wParam)
                    {
                        case WM_KEYDOWN:
                        case WM_SYSKEYDOWN:
                            if (KeyDown != null)
                            {
                                KeyDown(this, e);
                                handled = handled || e.Handled;
                            }
                            break;
                        case WM_KEYUP:
                        case WM_SYSKEYUP:
                            if (KeyUp != null)
                            {
                                KeyUp(this, e);
                                handled = handled || e.Handled;
                            }
                            break;
                    }
                    // Handle KeyPress event  
                    if (wParam == WM_KEYDOWN &&
                       !handled &&
                       !e.SuppressKeyPress &&
                        KeyPress != null)
                    {
                        byte[] keyState = new byte[256];
                        byte[] inBuffer = new byte[2];
                        GetKeyboardState(keyState);
                        if (ToAscii(keyboardHookStruct.vkCode,
                                  keyboardHookStruct.scanCode,
                                  keyState,
                                  inBuffer,
                                  keyboardHookStruct.flags) == 1)
                        {
                            char key = (char)inBuffer[0];
                            if ((capslock ^ shift) && Char.IsLetter(key))
                                key = Char.ToUpper(key);
                            KeyPressEventArgs e2 = new KeyPressEventArgs(key);
                            KeyPress(this, e2);
                            handled = handled || e.Handled;
                        }
                    }
                }
                if (handled)
                {
                    return 1;
                }
                else
                {
                    return CallNextHookEx(_handleToHook, nCode, wParam, lParam);
                }
            }
            #endregion
        }
        /// <summary>  
        /// Standard Keyboard Shortcuts used by most applications  
        /// </summary>  
        public enum StandardShortcut
        {
            Copy,
            Cut,
            Paste,
            SelectAll,
            Save,
            Open,
            New,
            Close,
            Print
        }
        /// <summary>  
        /// Simulate keyboard key presses  
        /// </summary>  
        public static class KeyboardSimulator
        {
            #region Windows API Code  
            const int KEYEVENTF_EXTENDEDKEY = 0x1;
            const int KEYEVENTF_KEYUP = 0x2;
            [DllImport("user32.dll")]
            static extern void keybd_event(byte key, byte scan, int flags, int extraInfo);
            #endregion
            #region Methods  
            public static void KeyDown(Keys key)
            {
                keybd_event(ParseKey(key), 0, 0, 0);
            }
            public static void KeyUp(Keys key)
            {
                keybd_event(ParseKey(key), 0, KEYEVENTF_KEYUP, 0);
            }
            public static void KeyPress(Keys key)
            {
                KeyDown(key);
                KeyUp(key);
            }
            public static void SimulateStandardShortcut(StandardShortcut shortcut)
            {
                switch (shortcut)
                {
                    case StandardShortcut.Copy:
                        KeyDown(Keys.Control);
                        KeyPress(Keys.C);
                        KeyUp(Keys.Control);
                        break;
                    case StandardShortcut.Cut:
                        KeyDown(Keys.Control);
                        KeyPress(Keys.X);
                        KeyUp(Keys.Control);
                        break;
                    case StandardShortcut.Paste:
                        KeyDown(Keys.Control);
                        KeyPress(Keys.V);
                        KeyUp(Keys.Control);
                        break;
                    case StandardShortcut.SelectAll:
                        KeyDown(Keys.Control);
                        KeyPress(Keys.A);
                        KeyUp(Keys.Control);
                        break;
                    case StandardShortcut.Save:
                        KeyDown(Keys.Control);
                        KeyPress(Keys.S);
                        KeyUp(Keys.Control);
                        break;
                    case StandardShortcut.Open:
                        KeyDown(Keys.Control);
                        KeyPress(Keys.O);
                        KeyUp(Keys.Control);
                        break;
                    case StandardShortcut.New:
                        KeyDown(Keys.Control);
                        KeyPress(Keys.N);
                        KeyUp(Keys.Control);
                        break;
                    case StandardShortcut.Close:
                        KeyDown(Keys.Alt);
                        KeyPress(Keys.F4);
                        KeyUp(Keys.Alt);
                        break;
                    case StandardShortcut.Print:
                        KeyDown(Keys.Control);
                        KeyPress(Keys.P);
                        KeyUp(Keys.Control);
                        break;
                }
            }
            static byte ParseKey(Keys key)
            {
                // Alt, Shift, and Control need to be changed for API function to work with them  
                switch (key)
                {
                    case Keys.Alt:
                        return (byte)18;
                    case Keys.Control:
                        return (byte)17;
                    case Keys.Shift:
                        return (byte)16;
                    default:
                        return (byte)key;
                }
            }
            #endregion
        }
        /// <summary>  
        /// Captures global mouse events  
        /// </summary>  
        public class MouseHook : GlobalHook
        {
            #region MouseEventType Enum  
            private enum MouseEventType
            {
                None,
                MouseDown,
                MouseUp,
                DoubleClick,
                MouseWheel,
                MouseMove
            }
            #endregion
            #region Events  
            public event MouseEventHandler MouseDown;
            public event MouseEventHandler MouseUp;
            public event MouseEventHandler MouseMove;
            public event MouseEventHandler MouseWheel;
            public event EventHandler Click;
            public event EventHandler DoubleClick;
            #endregion
            #region Constructor  
            public MouseHook()
            {
                _hookType = WH_MOUSE_LL;
            }
            #endregion
            #region Methods  
            protected override int HookCallbackProcedure(int nCode, int wParam, IntPtr lParam)
            {
                if (nCode > -1 && (MouseDown != null || MouseUp != null || MouseMove != null))
                {
                    MouseLLHookStruct mouseHookStruct =
                        (MouseLLHookStruct)Marshal.PtrToStructure(lParam, typeof(MouseLLHookStruct));
                    MouseButtons button = GetButton(wParam);
                    MouseEventType eventType = GetEventType(wParam);
                    MouseEventArgs e = new MouseEventArgs(
                        button,
                        (eventType == MouseEventType.DoubleClick ? 2 : 1),
                        mouseHookStruct.pt.x,
                        mouseHookStruct.pt.y,
                        (eventType == MouseEventType.MouseWheel ? (short)((mouseHookStruct.mouseData >> 16) & 0xffff) : 0));
                    // Prevent multiple Right Click events (this probably happens for popup menus)  
                    if (button == MouseButtons.Right && mouseHookStruct.flags != 0)
                    {
                        eventType = MouseEventType.None;
                    }
                    switch (eventType)
                    {
                        case MouseEventType.MouseDown:
                            if (MouseDown != null)
                            {
                                MouseDown(this, e);
                            }
                            break;
                        case MouseEventType.MouseUp:
                            if (Click != null)
                            {
                                Click(this, new EventArgs());
                            }
                            if (MouseUp != null)
                            {
                                MouseUp(this, e);
                            }
                            break;
                        case MouseEventType.DoubleClick:
                            if (DoubleClick != null)
                            {
                                DoubleClick(this, new EventArgs());
                            }
                            break;
                        case MouseEventType.MouseWheel:
                            if (MouseWheel != null)
                            {
                                MouseWheel(this, e);
                            }
                            break;
                        case MouseEventType.MouseMove:
                            if (MouseMove != null)
                            {
                                MouseMove(this, e);
                            }
                            break;
                        default:
                            break;
                    }
                }
                return CallNextHookEx(_handleToHook, nCode, wParam, lParam);
            }
            private MouseButtons GetButton(Int32 wParam)
            {
                switch (wParam)
                {
                    case WM_LBUTTONDOWN:
                    case WM_LBUTTONUP:
                    case WM_LBUTTONDBLCLK:
                        return MouseButtons.Left;
                    case WM_RBUTTONDOWN:
                    case WM_RBUTTONUP:
                    case WM_RBUTTONDBLCLK:
                        return MouseButtons.Right;
                    case WM_MBUTTONDOWN:
                    case WM_MBUTTONUP:
                    case WM_MBUTTONDBLCLK:
                        return MouseButtons.Middle;
                    default:
                        return MouseButtons.None;
                }
            }
            private MouseEventType GetEventType(Int32 wParam)
            {
                switch (wParam)
                {
                    case WM_LBUTTONDOWN:
                    case WM_RBUTTONDOWN:
                    case WM_MBUTTONDOWN:
                        return MouseEventType.MouseDown;
                    case WM_LBUTTONUP:
                    case WM_RBUTTONUP:
                    case WM_MBUTTONUP:
                        return MouseEventType.MouseUp;
                    case WM_LBUTTONDBLCLK:
                    case WM_RBUTTONDBLCLK:
                    case WM_MBUTTONDBLCLK:
                        return MouseEventType.DoubleClick;
                    case WM_MOUSEWHEEL:
                        return MouseEventType.MouseWheel;
                    case WM_MOUSEMOVE:
                        return MouseEventType.MouseMove;
                    default:
                        return MouseEventType.None;
                }
            }
            #endregion
        }
        /// <summary>  
        /// And X, Y point on the screen  
        /// </summary>  
        public struct MousePoint
        {
            public MousePoint(Point p)
            {
                X = p.X;
                Y = p.Y;
            }
            public int X;
            public int Y;
            public static implicit operator Point(MousePoint p)
            {
                return new Point(p.X, p.Y);
            }
        }
        /// <summary>  
        /// Mouse buttons that can be pressed  
        /// </summary>  
        public enum MouseButton
        {
            Left = 0x2,
            Right = 0x8,
            Middle = 0x20
        }
        /// <summary>  
        /// Operations that simulate mouse events  
        /// </summary>  
        public static class MouseSimulator
        {
            #region Windows API Code  
            [DllImport("user32.dll")]
            static extern int ShowCursor(bool show);
            [DllImport("user32.dll")]
            static extern void mouse_event(int flags, int dX, int dY, int buttons, int extraInfo);
            const int MOUSEEVENTF_MOVE = 0x1;
            const int MOUSEEVENTF_LEFTDOWN = 0x2;
            const int MOUSEEVENTF_LEFTUP = 0x4;
            const int MOUSEEVENTF_RIGHTDOWN = 0x8;
            const int MOUSEEVENTF_RIGHTUP = 0x10;
            const int MOUSEEVENTF_MIDDLEDOWN = 0x20;
            const int MOUSEEVENTF_MIDDLEUP = 0x40;
            const int MOUSEEVENTF_WHEEL = 0x800;
            const int MOUSEEVENTF_ABSOLUTE = 0x8000;
            #endregion
            #region Properties  
            /// <summary>  
            /// Gets or sets a structure that represents both X and Y mouse coordinates  
            /// </summary>  
            public static MousePoint Position
            {
                get
                {
                    return new MousePoint(Cursor.Position);
                }
                set
                {
                    Cursor.Position = value;
                }
            }
            /// <summary>  
            /// Gets or sets only the mouse's x coordinate  
            /// </summary>  
            public static int X
            {
                get
                {
                    return Cursor.Position.X;
                }
                set
                {
                    Cursor.Position = new Point(value, Y);
                }
            }
            /// <summary>  
            /// Gets or sets only the mouse's y coordinate  
            /// </summary>  
            public static int Y
            {
                get
                {
                    return Cursor.Position.Y;
                }
                set
                {
                    Cursor.Position = new Point(X, value);
                }
            }
            #endregion
            #region Methods  
            /// <summary>  
            /// Press a mouse button down  
            /// </summary>  
            /// <param name="button"></param>  
            public static void MouseDown(MouseButton button)
            {
                mouse_event(((int)button), 0, 0, 0, 0);
            }
            public static void MouseDown(MouseButtons button)
            {
                switch (button)
                {
                    case MouseButtons.Left:
                        MouseDown(MouseButton.Left);
                        break;
                    case MouseButtons.Middle:
                        MouseDown(MouseButton.Middle);
                        break;
                    case MouseButtons.Right:
                        MouseDown(MouseButton.Right);
                        break;
                }
            }
            /// <summary>  
            /// Let a mouse button up  
            /// </summary>  
            /// <param name="button"></param>  
            public static void MouseUp(MouseButton button)
            {
                mouse_event(((int)button) * 2, 0, 0, 0, 0);
            }
            public static void MouseUp(MouseButtons button)
            {
                switch (button)
                {
                    case MouseButtons.Left:
                        MouseUp(MouseButton.Left);
                        break;
                    case MouseButtons.Middle:
                        MouseUp(MouseButton.Middle);
                        break;
                    case MouseButtons.Right:
                        MouseUp(MouseButton.Right);
                        break;
                }
            }
            /// <summary>  
            /// Click a mouse button (down then up)  
            /// </summary>  
            /// <param name="button"></param>  
            public static void Click(MouseButton button)
            {
                MouseDown(button);
                MouseUp(button);
            }
            public static void Click(MouseButtons button)
            {
                switch (button)
                {
                    case MouseButtons.Left:
                        Click(MouseButton.Left);
                        break;
                    case MouseButtons.Middle:
                        Click(MouseButton.Middle);
                        break;
                    case MouseButtons.Right:
                        Click(MouseButton.Right);
                        break;
                }
            }
            /// <summary>  
            /// Double click a mouse button (down then up twice)  
            /// </summary>  
            /// <param name="button"></param>  
            public static void DoubleClick(MouseButton button)
            {
                Click(button);
                Click(button);
            }
            public static void DoubleClick(MouseButtons button)
            {
                switch (button)
                {
                    case MouseButtons.Left:
                        DoubleClick(MouseButton.Left);
                        break;
                    case MouseButtons.Middle:
                        DoubleClick(MouseButton.Middle);
                        break;
                    case MouseButtons.Right:
                        DoubleClick(MouseButton.Right);
                        break;
                }
            }
            /// <summary>  
            /// Show a hidden current on currently application  
            /// </summary>  
            public static void Show()
            {
                ShowCursor(true);
            }
            /// <summary>  
            /// Hide mouse cursor only on current application's forms  
            /// </summary>  
            public static void Hide()
            {
                ShowCursor(false);
            }
            #endregion
        }
    }
}
